using NICWebApi.Extensions.Caching.Interfaces;
using NICWebApi.Extensions.Caching.Options;

namespace NICWebApi.Extensions.Caching.Implementations;

/// <summary>
/// 分布式缓存服务实现
/// 提供基于Redis的分布式缓存操作，支持序列化和过期时间
/// </summary>
public class DistributedCacheService : ISimpleCacheService
{
    private readonly IDistributedCache _distributedCache;
    private readonly ISimpleCacheKeyGenerator _keyGenerator;
    private readonly CachingOptions _options;
    private readonly JsonSerializerOptions _jsonOptions;

    /// <summary>
    /// 初始化分布式缓存服务
    /// </summary>
    /// <param name="distributedCache">分布式缓存</param>
    /// <param name="keyGenerator">缓存键生成器</param>
    /// <param name="options">缓存选项</param>
    public DistributedCacheService(
        IDistributedCache distributedCache,
        ISimpleCacheKeyGenerator keyGenerator,
        IOptions<CachingOptions> options)
    {
        _distributedCache = distributedCache ?? throw new ArgumentNullException(nameof(distributedCache));
        _keyGenerator = keyGenerator ?? throw new ArgumentNullException(nameof(keyGenerator));
        _options = options?.Value ?? new CachingOptions();
        _jsonOptions = new JsonSerializerOptions
        {
            PropertyNameCaseInsensitive = true,
            WriteIndented = false
        };
    }

    /// <summary>
    /// 从分布式缓存中获取值
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="key"></param>
    /// <returns></returns>
    public T Get<T>(string key)
    {
        var normalizedKey = _keyGenerator.NormalizeKey(key);

        var bytes = _distributedCache.Get(normalizedKey);
        if (bytes == null || bytes.Length == 0)
        {
            return default;
        }

        return Deserialize<T>(bytes);
    }

    /// <summary>
    /// 从分布式缓存中异步获取值
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="key"></param>
    /// <param name="token"></param>
    /// <returns></returns>
    public async Task<T> GetAsync<T>(string key, CancellationToken token = default)
    {
        token.ThrowIfCancellationRequested();
        var normalizedKey = _keyGenerator.NormalizeKey(key);

        var bytes = await _distributedCache.GetAsync(normalizedKey, token).ConfigureAwait(false);
        if (bytes == null || bytes.Length == 0)
        {
            return default;
        }

        return Deserialize<T>(bytes);
    }

    /// <summary>
    /// 设置值到分布式缓存中
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="key"></param>
    /// <param name="value"></param>
    /// <param name="expiration"></param>
    /// <returns></returns>
    public bool Set<T>(string key, T value, int? expiration = null)
    {
        if (value == null)
        {
            return false;
        }

        var normalizedKey = _keyGenerator.NormalizeKey(key);
        var expirationSeconds = expiration ?? _options.DefaultExpirationSeconds;
        var cacheOptions = new DistributedCacheEntryOptions
        {
            AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(expirationSeconds)
        };

        var bytes = Serialize(value);
        _distributedCache.Set(normalizedKey, bytes, cacheOptions);
        return true;
    }

    /// <summary>
    /// 异步设置值到分布式缓存中
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="key"></param>
    /// <param name="value"></param>
    /// <param name="expiration"></param>
    /// <param name="token"></param>
    /// <returns></returns>
    public async Task<bool> SetAsync<T>(string key, T value, int? expiration = null, CancellationToken token = default)
    {
        token.ThrowIfCancellationRequested();
        if (value == null)
        {
            return false;
        }

        var normalizedKey = _keyGenerator.NormalizeKey(key);
        var expirationSeconds = expiration ?? _options.DefaultExpirationSeconds;
        var cacheOptions = new DistributedCacheEntryOptions
        {
            AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(expirationSeconds)
        };

        var bytes = Serialize(value);
        await _distributedCache.SetAsync(normalizedKey, bytes, cacheOptions, token).ConfigureAwait(false);
        return true;
    }

    /// <summary>
    /// 从分布式缓存中移除值
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    public bool Remove(string key)
    {
        var normalizedKey = _keyGenerator.NormalizeKey(key);
        _distributedCache.Remove(normalizedKey);
        return true;
    }

    /// <summary>
    /// 从分布式缓存中异步移除值
    /// </summary>
    /// <param name="key"></param>
    /// <param name="token"></param>
    /// <returns></returns>
    public async Task<bool> RemoveAsync(string key, CancellationToken token = default)
    {
        token.ThrowIfCancellationRequested();
        var normalizedKey = _keyGenerator.NormalizeKey(key);
        await _distributedCache.RemoveAsync(normalizedKey, token).ConfigureAwait(false);
        return true;
    }

    /// <summary>
    /// 移除所有匹配的键
    /// </summary>
    /// <param name="pattern"></param>
    /// <returns></returns>
    public int RemoveByPattern(string pattern)
    {
        return 0;
    }

    /// <summary>
    /// 异步移除所有匹配的键
    /// </summary>
    /// <param name="pattern"></param>
    /// <param name="token"></param>
    /// <returns></returns>
    public Task<int> RemoveByPatternAsync(string pattern, CancellationToken token = default)
    {
        token.ThrowIfCancellationRequested();
        return Task.FromResult(RemoveByPattern(pattern));
    }

    /// <summary>
    /// 检查键是否存在
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    public bool Exists(string key)
    {
        var normalizedKey = _keyGenerator.NormalizeKey(key);
        return _distributedCache.Get(normalizedKey) != null;
    }

    /// <summary>
    /// 异步检查键是否存在
    /// </summary>
    /// <param name="key"></param>
    /// <param name="token"></param>
    /// <returns></returns>
    public async Task<bool> ExistsAsync(string key, CancellationToken token = default)
    {
        token.ThrowIfCancellationRequested();
        var normalizedKey = _keyGenerator.NormalizeKey(key);
        return await _distributedCache.GetAsync(normalizedKey, token).ConfigureAwait(false) != null;
    }

    /// <summary>
    /// 获取或设置缓存
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="key"></param>
    /// <param name="valueFactory"></param>
    /// <param name="expiration"></param>
    /// <returns></returns>
    public T GetOrSet<T>(string key, Func<T> valueFactory, int? expiration = null)
    {
        var normalizedKey = _keyGenerator.NormalizeKey(key);
        var value = Get<T>(normalizedKey);
        if (value != null)
        {
            return value;
        }

        value = valueFactory();
        if (value != null)
        {
            Set(normalizedKey, value, expiration);
        }

        return value;
    }

    /// <summary>
    /// 异步获取或设置缓存
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="key"></param>
    /// <param name="valueFactory"></param>
    /// <param name="expiration"></param>
    /// <param name="token"></param>
    /// <returns></returns>
    public async Task<T> GetOrSetAsync<T>(string key, Func<Task<T>> valueFactory, int? expiration = null, CancellationToken token = default)
    {
        token.ThrowIfCancellationRequested();
        var normalizedKey = _keyGenerator.NormalizeKey(key);

        var value = await GetAsync<T>(normalizedKey, token).ConfigureAwait(false);
        if (value != null)
        {
            return value;
        }

        value = await valueFactory().ConfigureAwait(false);
        if (value != null)
        {
            await SetAsync(normalizedKey, value, expiration, token).ConfigureAwait(false);
        }

        return value;
    }

    /// <summary>
    /// 获取所有匹配的键
    /// </summary>
    /// <param name="pattern"></param>
    /// <returns></returns>
    public IEnumerable<string> GetKeysByPattern(string pattern)
    {
        return Enumerable.Empty<string>();
    }

    /// <summary>
    /// 异步获取所有匹配的键
    /// </summary>
    /// <param name="pattern"></param>
    /// <param name="token"></param>
    /// <returns></returns>
    public Task<IEnumerable<string>> GetKeysByPatternAsync(string pattern, CancellationToken token = default)
    {
        token.ThrowIfCancellationRequested();
        return Task.FromResult(GetKeysByPattern(pattern));
    }

    /// <summary>
    /// 清空缓存
    /// </summary>
    public void Clear()
    {
    }

    /// <summary>
    /// 异步清空缓存
    /// </summary>
    /// <param name="token"></param>
    /// <returns></returns>
    public Task ClearAsync(CancellationToken token = default)
    {
        token.ThrowIfCancellationRequested();
        Clear();
        return Task.CompletedTask;
    }

    /// <summary>
    /// 获取缓存的过期时间
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    public TimeSpan? GetExpiration(string key)
    {
        return null;
    }

    /// <summary>
    /// 异步获取缓存的过期时间
    /// </summary>
    /// <param name="key"></param>
    /// <param name="token"></param>
    /// <returns></returns>
    public Task<TimeSpan?> GetExpirationAsync(string key, CancellationToken token = default)
    {
        token.ThrowIfCancellationRequested();
        return Task.FromResult(GetExpiration(key));
    }

    /// <summary>
    /// 刷新缓存
    /// </summary>
    /// <param name="key"></param>
    /// <param name="expiration"></param>
    /// <returns></returns>
    public bool Refresh(string key, int? expiration = null)
    {
        var normalizedKey = _keyGenerator.NormalizeKey(key);
        var value = Get<object>(normalizedKey);
        if (value != null)
        {
            return Set(normalizedKey, value, expiration);
        }
        return false;
    }

    /// <summary>
    /// 异步刷新缓存
    /// </summary>
    /// <param name="key"></param>
    /// <param name="expiration"></param>
    /// <param name="token"></param>
    /// <returns></returns>
    public async Task<bool> RefreshAsync(string key, int? expiration = null, CancellationToken token = default)
    {
        token.ThrowIfCancellationRequested();
        var normalizedKey = _keyGenerator.NormalizeKey(key);
        var value = await GetAsync<object>(normalizedKey, token).ConfigureAwait(false);
        if (value != null)
        {
            return await SetAsync(normalizedKey, value, expiration, token).ConfigureAwait(false);
        }
        return false;
    }

    /// <summary>
    /// 序列化对象为字节数组
    /// </summary>
    /// <typeparam name="T">对象类型</typeparam>
    /// <param name="value">要序列化的对象</param>
    /// <returns>序列化后的字节数组</returns>
    private byte[] Serialize<T>(T value)
    {
        if (value == null)
        {
            return null;
        }

        if (value is string stringValue)
        {
            return Encoding.UTF8.GetBytes(stringValue);
        }

        var json = JsonSerializer.Serialize(value, _jsonOptions);
        return Encoding.UTF8.GetBytes(json);
    }

    /// <summary>
    /// 从字节数组反序列化对象
    /// </summary>
    /// <typeparam name="T">对象类型</typeparam>
    /// <param name="bytes">要反序列化的字节数组</param>
    /// <returns>反序列化后的对象</returns>
    private T Deserialize<T>(byte[] bytes)
    {
        if (bytes == null || bytes.Length == 0)
        {
            return default;
        }

        var json = Encoding.UTF8.GetString(bytes);
        if (typeof(T) == typeof(string))
        {
            return (T)(object)json;
        }

        return JsonSerializer.Deserialize<T>(json, _jsonOptions);
    }
}